public class State
{
	/*
	 * MEMBER VARIABLES
	 */
	
	protected String _name;
	// Is it an accepting state?  
	protected boolean _accepting;
	// Store its transition information.  
	// Only stores the name of states it transitions to, due to way 
	// states update themselves (Wouldn't be efficient to update them here,
	// so we'd only have the name to go on anyways)
	// Even indices store letters, odd ones states
	protected String[] _transitions = new String[50];
	protected int _transitionCount = 0;
	// Store the state coordinates on screen, if any
	// Values of -1 indicate none provided (Can't be null, int[] won't allow)
	protected int[] _coords = new int[2];
	
	
	
	/*
	 * CONSTRUCTORS
	 */
	
	public State(String name, String[] coords)
	{
		this._name = name;
		this._accepting = false;
		this._coords[0] = Integer.parseInt(coords[0]);
		this._coords[1] = Integer.parseInt(coords[1]);
	}
	
	public State(String name)
	{
		this._name = name;
		this._accepting = false;
		this._coords[0] = -1;
		this._coords[1] = -1;
	}
	
	public State(String name, String[] coords, String[] transitions)
	{
		this._name = name;
		this._accepting = false;
		this._coords[0] = Integer.parseInt(coords[0]);
		this._coords[1] = Integer.parseInt(coords[1]);
		this.parseTransitions(transitions);
	}
	
	
	
	/*
	 * CONCRETE METHODS
	 */
	
	// Increases the size of the transition arrays
	public void increaseTransitions()
	{
		String[] newTransitions = new String[this._transitions.length + 100];
		for (int i = 0; i < this._transitions.length; i++)
		{
			newTransitions[i] = this._transitions[i];
		}
		this._transitions = newTransitions;
	}
	
	// Adds a transition, if it does not already exist.  
	public boolean addTransition(State resultState, String letter)
	{
		for (int i = 0; i < this._transitionCount; i++)
		{
			if (this._transitions[2 * i].equals(letter)
				&& this._transitions[2 * i + 1].equals(resultState.getName()))
			{
				return false; // Transition already exists
			}
		}
		if (2 * this._transitionCount == this._transitions.length)
		{
			this.increaseTransitions();
		}
		this._transitions[2 * this._transitionCount] = letter;
		this._transitions[2 * this._transitionCount + 1] = resultState.getName();
		this._transitionCount++;
		return true;
	}
	
	// Removes a transition from this state.  Returns true if successful.  
	public boolean removeTransition(State state, String letter)
	{
		for (int i = 0; i < this._transitionCount; i++)
		{
			if (this._transitions[2 * i].equals(letter) 
				&& this._transitions[2 * i + 1].equals(state.getName()))
			{
				for (int j = i; j < this._transitionCount - 1; j++)
				{
					this._transitions[2 * j] = this._transitions[2 * j + 2];
					this._transitions[2 * j + 1] = this._transitions[2 * j + 3];
				}
				this._transitions[2 * this._transitionCount] = null;
				this._transitions[2 * this._transitionCount + 1] = null;
				this._transitionCount--;
				return true;
			}
		}
		return false;
	}
	
	// Removes all transitions from this state resulting in state.  
	public void removeAllTransitions(State state)
	{
		for (int i = 0; i < this._transitionCount; i++)
		{
			if (this._transitions[2 * i + 1].equals(state.getName()))
			{
				for (int j = i; j < this._transitionCount - 1; j++)
				{
					this._transitions[2 * j] = this._transitions[2 * j + 2];
					this._transitions[2 * j + 1] = this._transitions[2 * j + 3];
				}
				this._transitions[2 * this._transitionCount] = null;
				this._transitions[2 * this._transitionCount + 1] = null;
				this._transitionCount--;
			}
		}
	}
	
	/*
	 * This function gets passed all of the transition data from the save
	 * file.  It figures out which transitions start with this state, and
	 * stores that information in this state's transition arrays.  Since 
	 * this information is from the save file, it assumes all letters and
	 * states given to it are actually in the FA.  A check for these things
	 * can be easily added if you think save files will ever be saved 
	 * incorrectly for some reason.  
	 */
	public void parseTransitions(String[] transitions)
	{
		for (String trans : transitions)
		{
			if (trans.split("\\+")[0].equals(this._name))
			{
				String[] otherStuff = trans.split("\\+")[1].split("=");
				if (2*this._transitionCount == this._transitions.length)
				{
					this.increaseTransitions();
				}
				this._transitions[2 * this._transitionCount] = otherStuff[0];
				this._transitions[2 * this._transitionCount + 1] = otherStuff[1];
				this._transitionCount++;
			}
		}
	}
	
	// Assumes this state is in a DFA, and returns the name of the
	// first state mapped to by the letter specified.  
	public String DFAtrans(String letter)
	{
		for (int i = 0; i < this._transitionCount; i++)
		{
			if (this._transitions[2 * i].equals(letter))
			{
				return this._transitions[2 * i + 1];
			}
		}
		return null; // This state lacks a transition for this letter
	}
	
	// Assumes this state is in an NFA, and returns all of the states
	// mapped to by the letter specified.  
	public String[] NFAtrans(String letter, int size)
	{
		String[] transitions = new String[size];
		int count = 0;
		for (int i = 0; i < this._transitionCount; i++)
		{
			if (this._transitions[2 * i].equals(letter))
			{
				transitions[count] = this._transitions[2 * i + 1];
				count++;
			}
		}
		String[] transitions2 = new String[count];
		for (int i = 0; i < count; i++) { transitions2[i] = transitions[i]; }
		return transitions2;
	}
	
	// Returns this state's transition data in text format.  
	public String getTransitionData()
	{
		String transitions = "";
		boolean anyYet = false;
		for (int i = 0; i < this._transitionCount; i++)
		{
			if (anyYet)
			{
				transitions += ",";
			}
			transitions += this._name + "+";
			transitions += this._transitions[2 * i] + "=";
			transitions += this._transitions[2 * i + 1];
			anyYet = true;
		}
		return transitions;
	}
	
	public int countSelfTransitionsBeforeB(int B)
	{
		int count = 0;
		for (int i = 0; i < B; i++)
		{
			if (this._transitions[2*i+1].equals(this._name))
			{
				count++;
			}
		}
		return count;
	}
	
	public void drawTransitions(ProxyDiagram pd, FiniteAutomata fa)
	{
		for (int i = 0; i < this._transitionCount; i++)
		{
			int s1i = fa.getIndexFromName(this.getName());
			int s2i = fa.getIndexFromName(this._transitions[2*i+1]);
			String addOn = "";
			if (this._transitions[2*i+1].equals(this._name))
			{
				for (int j = 0; j <  countSelfTransitionsBeforeB(i); j++)
				{
					addOn += "   ,";
				}
			}
			pd.drawTransition(s1i, s2i, addOn + this._transitions[2*i]);
		}
	}
	
	
	
	/*
	 * GETTERS AND SETTERS
	 */
	
	public String getName()
	{
		return this._name;
	}
	
	public void setName(String name)
	{
		this._name = name;
	}
	
	public boolean getAccepting()
	{
		return this._accepting;
	}
	
	public void setAccepting(boolean value)
	{
		this._accepting = value;
	}
	
	public int[] getCoords()
	{
		return this._coords;
	}
	
	public void setCoords(int[] coords)
	{
		this._coords = coords;
	}
	
	public String[] getTransitions()
	{
		return this._transitions;
	}
	
	public int getTransitionCount()
	{
		return this._transitionCount;
	}
}